package naming

import (
	"github.com/nacos-group/nacos-sdk-go/v2/clients"
	"github.com/nacos-group/nacos-sdk-go/v2/clients/naming_client"
	"github.com/nacos-group/nacos-sdk-go/v2/common/constant"
	"github.com/nacos-group/nacos-sdk-go/v2/vo"
	"go-main/library/log"
	"go-main/library/net/rpc/warden/resolver/nacos"
	"google.golang.org/grpc"
	"net"
	"os"
	"path/filepath"
	"strconv"
	"strings"
	"sync"
)

var _ IName = ncs{}

var _defaultNcsClient *ncs
var _ncsOnce sync.Once

type ncs struct {
	cfg    *config
	client naming_client.INamingClient
}

func NewNacos(c *config) IName {
	_ncsOnce.Do(func() {
		var (
			sip          = "localhost"
			sport uint64 = 8848
		)
		if c.Namespace == "" || c.Address == "" {
			panic("nacos addr and namespace is empty")
		}
		sa := strings.Split(c.Address, ":")
		if len(sa) == 2 {
			sip = sa[0]
			sport, _ = strconv.ParseUint(sa[1], 10, 64)
		}
		sc := []constant.ServerConfig{
			//*constant.NewServerConfig("118.195.198.233", 8849),
			*constant.NewServerConfig(sip, sport),
		}
		//create ClientConfig
		cliCfg := *constant.NewClientConfig(
			//constant.WithNamespaceId("71dc524c-a97e-40cd-964f-c968f8c7ee7e"),
			constant.WithNamespaceId(c.Namespace),
			constant.WithTimeoutMs(5000),
			constant.WithNotLoadCacheAtStart(true),
			constant.WithLogDir(filepath.Join(os.TempDir(), "nacos", "log")),
			constant.WithCacheDir(filepath.Join(os.TempDir(), "nacos", "cache")),
			//constant.WithLogLevel("debug"),
		)

		// create naming client
		client, err := clients.NewNamingClient(
			vo.NacosClientParam{
				ClientConfig:  &cliCfg,
				ServerConfigs: sc,
			},
		)
		if err != nil {
			panic(err)
		}
		_defaultNcsClient = &ncs{client: client, cfg: c}
	})

	return _defaultNcsClient
}

func (n ncs) RegisterInstance(appId string) error {
	success, err := n.client.RegisterInstance(vo.RegisterInstanceParam{
		Ip:          localIP(),
		Port:        9000,
		ServiceName: appId,
		GroupName:   n.cfg.Namespace,
		ClusterName: "cluster-a",
		Weight:      10,
		Enable:      true,
		Healthy:     true,
		Ephemeral:   true,
		//Metadata:    map[string]string{"idc": "shanghai"},
	})
	if !success || err != nil {
		log.Error("RegisterServiceInstance failed! err:", err)
		//panic(fmt.Sprintf("RegisterServiceInstance failed!,err:(%+v)", err))
		return err
	}
	return nil
}

func (n ncs) RegisterResolver() grpc.DialOption {
	return grpc.WithResolvers(&nacos.ResolverBuilder{Client: n.client})
	//resolver.Register()
}

func (ncs) Close() error {
	return nil
}

// LocalIP return local IP of the host.
func localIP() string {
	addrs, err := net.InterfaceAddrs()
	if err != nil {
		return ""
	}
	for _, address := range addrs {
		// check the address type and if it is not a loopback the display it
		if ipnet, ok := address.(*net.IPNet); ok && !ipnet.IP.IsLoopback() {
			if ipnet.IP.To4() != nil {
				return ipnet.IP.String()
			}
		}
	}
	return ""
}
